package com.example.OnlineStorage.util;

import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;

/**
 * SHA256工具类，提供计算字符串和文件的SHA-256哈希值的功能。
 */
@Component
public class SHA256 {
	
	/**
	 * 计算字符串的SHA-256哈希值。
	 *
	 * @param password 需要计算哈希值的字符串。
	 * @return 字符串的SHA-256哈希值。
	 * @throws NoSuchAlgorithmException 如果SHA-256算法不可用。
	 */
	/**
	 * 计算密码的SHA-256哈希值。
	 *
	 * @param password 需要计算哈希值的密码。
	 * @return 计算后的SHA-256哈希值。
	 * @throws NoSuchAlgorithmException 如果请求的摘要算法不存在。
	 */
	public static String calculateSha256Hash ( String password ) throws NoSuchAlgorithmException {
		MessageDigest digest = MessageDigest.getInstance( "SHA-256" );
		digest.update( password.getBytes( ) );
		return bytesToHex( digest.digest( ) );
	}
	

	/**
	 * 将字节数组转换为十六进制字符串。
	 *
	 * @param bytes 输入的字节数组。
	 * @return 转换后的十六进制字符串。
	 */
	private static String bytesToHex ( byte[] bytes ) {
		StringBuilder result = new StringBuilder( );
		
		// 遍历字节数组，转换为十六进制字符串
		for ( byte b : bytes ) {
			result.append( String.format( "%02x", b & 0xff ) );
		}
		return result.toString( );
	}
	
	/**
	 * 计算文件的SHA-256哈希值。
	 *
	 * @param filePath 需要计算哈希值的文件路径。
	 * @return 计算后的SHA-256哈希值。
	 */
	public static String calculateFileSHA256 ( String filePath ) {
		try {
			MessageDigest digest = MessageDigest.getInstance( "SHA-256" );
			try ( FileInputStream fis = new FileInputStream( filePath ) ) {
				byte[] buffer = new byte[1024];
				int read;
				while ( ( read = fis.read( buffer ) ) != - 1 ) {
					digest.update( buffer, 0, read );
				}
			}
			return bytesToHex( digest.digest( ) );
		} catch ( Exception e ) {
			throw new RuntimeException( "文件SHA-256计算失败", e );
		}
	}
	
	/**
	 * 计算文件的SHA-256哈希值。
	 *
	 * @param file 需要计算哈希值的文件。
	 * @return 计算后的SHA-256哈希值。
	 */
	public static String calculateFileSHA256 ( MultipartFile file ) {
		try {
			MessageDigest digest = MessageDigest.getInstance( "SHA-256" );
			try ( InputStream fis = file.getInputStream( ) ) {
				byte[] buffer = new byte[1024];
				int read;
				while ( ( read = fis.read( buffer ) ) != - 1 ) {
					digest.update( buffer, 0, read );
				}
			}
			return bytesToHex( digest.digest( ) );
		} catch (Exception e) {
			throw new RuntimeException("文件SHA-256计算失败", e);
		}
	}
	
	
	/**
	 * 根据一组 SHA-256 值进行一次 增量计算
	 *
	 * @param SHA256 SHA-256数组值
	 * @return String intactSHA256
	 */
	public static String calculateIncrementalSHA256 (List<String> SHA256) {
		try {
			MessageDigest digest = MessageDigest.getInstance("SHA-256");
			for (String sha256 : SHA256) {
				digest.update(sha256.getBytes());
			}
			return bytesToHex(digest.digest());
		} catch ( Exception e ) {
			throw new RuntimeException( "文件SHA-256计算失败", e );
		}
	}
	
	/**
	 * 测试 文件分块计算SHA-256值,和前端的区别
	 *
	 * @param filePath      文件路径
	 * @param ChunkSize     分块大小
	 * @param startChunkNum 起始分块号
	 * @param endChunkNum   结束分块号
	 * @return String[]
	 */
	public static String[] calculateChunkSHA256 (String filePath, long ChunkSize, int startChunkNum, int endChunkNum) {
		try {
			String[] SHA_256s = new String[endChunkNum - startChunkNum];
			for (int i = startChunkNum; i < endChunkNum; i++) {
				//按照分块大小，计算每个分块的SHA-256值
				//				System.out.println("计算分块" + i + "的SHA-256值");
				MessageDigest digest = MessageDigest.getInstance("SHA-256");
				try (FileInputStream fis = new FileInputStream(filePath)) {
					long fileSize = Files.size(Paths.get(filePath));
					long remainingBytes = fileSize - i * ChunkSize;
					int size = remainingBytes > ChunkSize ? (int) ChunkSize : (int) remainingBytes;
					byte[] buffer = new byte[size];
					fis.skip(i * ChunkSize);
					fis.read(buffer);
					digest.update(buffer);
					SHA_256s[i] = bytesToHex(digest.digest());
				}
				
			}
			return SHA_256s;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
}
